#encoding=utf8
import datetime
from django import *
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import *
from django.contrib.comments import forms
from django.core import *
from django.core.paginator import *
from django.core.urlresolvers import *
from django.db import transaction
from django.db.models import *
from django.db.models.query_utils import Q
from django.forms.forms import *
from django.http import *
from django.http.response import *
from django.shortcuts import *
from django.views.decorators.http import *
import json

from trp.models import *
from utils.JsonResponse import *
from utils.decorators import *
from utils.utils import *
from website.settings import LOGGER as logger

from trp.views.costlog import get_cost_by_position
from django.template.defaultfilters import floatformat
MAX_INT=2147483647

@login_required
@require_GET
def main(request):
    account = request.user.account
    if account.is_admin():
        mediaId = request.GET.get("mediaId")
        return render_to_response('trp/position.html', {'user' : request.user, 'page' : 'media',"mediaId":mediaId})
    else:
        return JsonResponseBadrequest({"message":str("权限不足")})    
   

@login_required_ajax
@transaction.atomic
def do_modify(request):
    try :
        account = request.user.account
        if not account.is_admin():
            raise Exception("权限不足")
        param = json.loads(request.body)
        pid = int(param.get("position_id"))
        name = param.get("name").encode("utf-8")
        attrs_ids = param.get("attrs")
        width = param.get("width")
        mediaId = param.get("mediaId")
        height=param.get("height")
        mtypes = param.get("types")
        sizeLimit = param.get("size")or MAX_INT
        maxv = param.get("max") or 1
        minv = maxv
        p = None
        show_type=int(param.get("showType"))
        switch_time=param.get("time",0)
        array_type=param.get("arrayType",0)
        code=param.get("code",'')
        with transaction.atomic():
            p = Position.objects.prefetch_related("attrs","types").get(pk = pid,deleted=False)
            old_name=p.name.encode("utf-8")
            old_width=p.width
            old_height=p.height
            old_attrs_ids=[]
            for obj in p.attrs.all():
                old_attrs_ids.append(obj.id)
            old_size=p.size
            old_types_ids=[]
            for obj in p.types.all():
                old_types_ids.append(obj.id)
            old_max=p.max
            old_showType=p.show_type
            
            if int(mediaId) <0:
                raise Exception("media is illegal")
            p.media = Media.objects.get(pk=int(mediaId))
            if not name :
                raise Exception("name can not be empty")
            p.name=name
            if int(width)<=0 or int(height)<=0 :
                raise Exception("width or height is illegal")
            if not sizeLimit :
                sizeLimit  = MAX_INT
            width=int(width)
            height=int(height)
            p.width = width
            p.height=height
            types = MaterialType.objects.filter(id__in=[int(e) for e in (mtypes) or []])
            p.types.clear()
            p.types = types
            attrs = PositionAttr.objects.filter(id__in = [int(e) for e in attrs_ids or []])
            p.attrs.clear()
            p.attrs = attrs
            if int(sizeLimit)<=0 :
                raise Exception("position size limit is illegal")
            sizeLimit = int(sizeLimit)
            if sizeLimit != MAX_INT :
                sizeLimit = sizeLimit*1024
            p.size = sizeLimit
            minv = int(minv)
            maxv = int(maxv)
            if minv<0 or maxv<0 or minv>maxv :
                raise Exception("position min or max is illegal")
            else :
                p.min = minv
                p.max = maxv
            p.last_update = datetime.datetime.now()
            p.show_type=show_type
            p.switch_time=switch_time
            p.arrange_type=array_type
            p.code=code
            p.save()
            
            details=""
            if cmp(old_name,name):
                details="名称:"+name+";"
            if old_height!=height or old_width!=width:
                details+="宽:"+str(width)+",高:"+str(height)+";"
            if old_max!=maxv:
                details+="分栏数:"+str(maxv)+";"
            attr_str=""
            if not attrs_ids:
                attrs_ids=[]
            old_set=set(old_attrs_ids)
            new_set=set(attrs_ids)
            if old_set!= new_set:
                for attr in attrs:
                    attr_str+=attr.name.encode("utf-8")+","
                count=len(attr_str)
                attr_str=attr_str[:count-1]
                attr_str="广告位属性:"+attr_str
                details+=attr_str+";" 
            type_str=""
            old_set=set(old_types_ids)
            new_set=set(mtypes) 
            if old_set!= new_set:
                for type in types:
                    type_str+=type.name.encode("utf-8")+","
                count=len(type_str)
                type_str=type_str[:count-1]
                type_str="素材类型:"+type_str
                details+=type_str+";"     
            if old_showType!=show_type:
                showType_str="展示类型:"
                if show_type==0:
                    showType_str+="默认"
                elif show_type==1:
                    showType_str+="轮播图"
                elif show_type==2:
                    showType_str+="banner"
                else:
                    showType_str+="自定义模板"
                details+=showType_str+";"
                        
            operation_log=OperationLog()
            operation_log.operation="修改"
            operation_log.object="广告位"
            operation_log.user=request.user      
            operation_log.object_id= pid
            operation_log.details=details 
            operation_log.save()
                
        
        
    except Exception,e :
        logger.exception(e)
        return JsonResponseBadrequest({"message":str(e)})

    return JsonResponse({"message":"ok"})

@login_required_ajax
@require_GET
@transaction.atomic
def do_delete(request):    
    try :
        account = request.user.account
        if not account.is_admin():
            raise Exception("权限不足")
        p = None
        pid =request.GET.get("position_id")
        p = Position.objects.get(id=int(pid),deleted=False)
#         p = Position.objects.filter(id=int(pid),deleted=False)[0]
        trafficCount = p.traffic_set.all().filter(deleted=False).count()
        if trafficCount >0 :
            print '######traffic count ######',trafficCount 
            return JsonResponseBadrequest({"message":"position(id=%s) cannot be deleted"%pid})
        else :
            with transaction.atomic():
                p.deleted=True
                p.save()
                p.attrs.clear()
                p.types.clear()
            operation_log=OperationLog()
            operation_log.operation="删除"
            operation_log.object="广告位"
            operation_log.user=request.user      
            operation_log.object_id= int(pid)
            operation_log.save()
    except Exception,e:
        logger.exception(e)
        return JsonResponseBadrequest({"message":str(e)})

    return JsonResponse({"message":"ok"})

@login_required_ajax
@transaction.atomic
def do_create(request):
    data = {}
    try :
        account = request.user.account
        if not account.is_admin():
            raise Exception("权限不足")
        data = json.loads(request.body)
        name = data.get("name","")
        attrsId = [int(e) for e in  data.get("attrs") or []]
        mediaId = data.get("mediaId") or -1
        width = data.get("width")
        height = data.get("height")
        size = data.get("size") or MAX_INT
        maxv =data.get("max") or 1
        minv = maxv
        typesId = [int(e) for e in  data.get("types")]
        media =None
        show_type=data.get("showType")
        switch_time=data.get("time",0)
        array_type=data.get("arrayType",0)
        code=data.get("code",'')
        try :
            maxv = int(maxv)
            minv = int(minv)
            media =Media.objects.get(pk=mediaId,deleted=False)
        except :
            raise Exception("media is illegal")

        if not int(width) or not int(height):
            raise Exception("width or height is isllegal")
        size = int(size)
        if size != MAX_INT :
            size = size * 1024
            size_str="大小限制:"+str(size)+";"
        
        with transaction.atomic():
            p = Position(name=name,width= width,height=height,size=size,media=media,min=minv,max=maxv)
            attrs = PositionAttr.objects.filter(id__in=attrsId)
            types = MaterialType.objects.filter(id__in=typesId)
            p.show_type=show_type
            p.switch_time=switch_time
            p.arrange_type=array_type
            p.code=code
            p.save()
            p.attrs=attrs
            p.types=types
        details="名称:"+name.encode("utf-8")+";"+"宽:"+str(width)+",高:"+str(height)+";分栏数:"+str(maxv)+";"
        attr_str=""
        for attr in attrs:
            attr_str+=attr.name.encode("utf-8")+","
        if attrs:
            count=len(attr_str)
            attr_str=attr_str[:count-1]
            attr_str="广告位属性:"+attr_str
            details+=attr_str+";"
        if types:
            type_str=""
            for type in types:
                type_str+=str(type.name)+","
            count=len(type_str)
            type_str=type_str[:count-1]
            type_str="素材类型:"+type_str
            details+=type_str+";"    
        showType_str="展示类型:"
        if show_type==0:
            showType_str+="默认"
        elif show_type==1:
            showType_str+="轮播图"
        elif show_type==2:
            showType_str+="banner"
        else:
            showType_str+="自定义模板"
        details+=showType_str+";"        
        operation_log=OperationLog()
        operation_log.operation="新建"
        operation_log.object="广告位"
        operation_log.user=request.user
        operation_log.details=details      
        operation_log.object_id=p.id 
        operation_log.save()
    except Exception,e:
        logger.exception(e)
        return JsonResponseBadrequest({'message':str(e)})

    return JsonResponse({"message":"ok"})

@login_required_ajax
def get_positions(request):
    try:
        account = request.user.account
        if not account.is_admin():
            raise Exception("权限不足")
        param = json.loads(request.body)
        searchTxt = param.get("searchTxt","")
        width=param.get("width")
        height=param.get("height")
        pageNo = param.get('pageNo',1)
        pageSize = param.get("pageSize",10)
        mediaId = int(param.get("mediaId",-1))
        qset =None
        data=None
        count=0
        
        args=[]
        args.append(Q(deleted=False))
        if mediaId != -1:
            args.append(Q(media_id=mediaId))            
        if searchTxt:
            args.append(Q(name__icontains=searchTxt)|Q(attrs__name__icontains=searchTxt))
        if width and height:
            args.append(Q(width=int(width),height=int(height)))

        qset = qset = Position.objects.prefetch_related("attrs","types").filter(*args).order_by("-id").distinct()

        paginator = Paginator(qset, pageSize)

        try:
            data = paginator.page(pageNo)
            count=paginator.count
        except PageNotAnInteger:
            data = paginator.page(1)
        except EmptyPage:
            data = paginator.page(paginator.num_pages)
        dataArr=[]
        if  data:
            for ele in data.object_list:
                ele_n = {}
                ele_n["id"]=ele.id
                ele_n["name"]=ele.name             
                data_attrs=[attr.name for attr in  ele.attrs.all()]
                ele_n["attrs"]=data_attrs
                ele_n["width"] = ele.width
                ele_n["height"] = ele.height
                ele_n["showType"] = ele.show_type
                ele_n["max"]=ele.max
                ele_n["min"]= ele.min
                ele_n["types"]=join_list([t.name for t in ele.types.all()])
                if ele.size ==MAX_INT :
                    ele_n["size"] = "--"
                else :
                    ele_n["size"]=ele.size/1024
                ele_n["can_deleted"]=True
                if ele.traffic_set.filter(deleted=False).exists():
                    ele_n["can_deleted"]=False
                dataArr.append(ele_n)
        result={}
        result["bodyData"]=dataArr
        result["pageSize"]=pageSize
        result["pageNo"]=pageNo
        result["totalCount"]=count
    except Exception,e:
        logger.exception(e)
        return JsonResponseBadrequest({'message':str(e)})
    return JsonResponse(result)

@login_required_ajax
@require_GET
def get_position(request):    
    try :
        account = request.user.account
        if not account.is_admin():
            raise Exception("权限不足")
        pid = request.GET.get("id",-1)
        ele_n={}
        position = Position.objects.prefetch_related("attrs","types").get(pk=int(pid))
        ele_n["id"] = position.id
        ele_n["name"]=position.name
        ele_n["attrs"] = [{"id":att.id,"name":att.name}for att in position.attrs.all()]
        ele_n["width"] = position.width
        ele_n["height"] = position.height
        ele_n["max"]=position.max
        ele_n["min"]= position.min
        ele_n["types"]=[{"id":p.id,"name":p.name}for p in position.types.all()]
        if position.size ==MAX_INT :
            ele_n["size"]="--"
        else :
            ele_n["size"]=position.size/1024
            
        ele_n["can_deleted"]=position.traffic_set.all().filter(deleted=False).count >0 and 1 or 0
        ele_n["showType"]=position.show_type
        ele_n["time"]=position.switch_time
        ele_n["arrayType"]=position.arrange_type
        ele_n["code"]=position.code
    except Exception,e:
        logger.exception(e)
        return JsonResponseBadrequest({"message":str(e)})
    return JsonResponse(ele_n)

@login_required_ajax
@require_GET
def get_position_code(request):
    position = Position.objects.get(id=request.GET['position_id'])
    url_prefix = website.settings.ADSERVING_URL
    if not url_prefix.endswith('/'):
        url_prefix += '/'

    data = {}
    data['prefix'] = '%ssemiad_iframe.html' % url_prefix
    data['width'] = position.width
    data['height'] = position.height
    data['showType'] = position.show_type
    data['max'] = position.max
    data['arrayType'] = position.arrange_type
    data['code'] = position.code
    data['time'] = position.switch_time
    data['serving'] = '%ssemi_ad_serving.js' % url_prefix

    return JsonResponse(data)


@login_required_ajax
@require_GET
def get_position_report(request):
    """
    根据广告位ID，起止日期的pv uv click ctr信息
    """
    
    try:
        account = request.user.account
        if not account.is_admin():
            raise Exception("权限不足")
        params=request.GET
        pid=int(params.get("position_id",-1))

        start_date = params.get("start")
        end_date = params.get("end")
        position = None
        start = datetime.datetime.strptime(start_date,"%Y-%m-%d").date()
        end = datetime.datetime.strptime(end_date,"%Y-%m-%d").date()
        if start >end or end >=datetime.datetime.today().date():
            raise Exception("start or end date is illegal")

        position = Position.objects.get(pk =pid,deleted=False)
        position_data = DailyPositionReport.objects.\
                                                    filter(date__range=(start,end),
                                                           position_id=pid).\
                                                    values_list("date","pv","uv","click","cost")
                                                    
        position_traffics = Traffic.objects.filter(Q(start__range=(start,end)) | Q(end__range=(start,end))|Q(start__lte=start,end__gte=end)|Q(start__gte=start,end__lte=end),Q(deleted=False),Q(position_id=pid))
#         traffic_id_arr=list(position_traffics.values_list("id",flat=True))
#         resources=Resource.objects.select_related().filter(Q(start__range=(start,end)) | Q(end__range=(start,end))|Q(start__lte=start,end__gte=end)|Q(start__gte=start,end__lte=end),Q(deleted=False),Q(traffic__in=traffic_id_arr))
        dateArr = date_range_array(start,end)
        position_data_by_date ={}
        for pd in position_data :
            d,pv,uv,click,cost=pd
            position_data_by_date[d]=(pv,uv,click,cost)
            
        resource_cost_by_day=__get_media_cost_by_day(position_traffics, position_data_by_date, dateArr)
        
        data = []
        for d in dateArr :
            pv,uv,click,income = position_data_by_date.get(d,(0,0,0,0))
            tmp = {}
            tmp["date"]=d.strftime("%Y-%m-%d")
            tmp["pv"]=pv
            tmp["uv"]=uv
            tmp["click"]=click
            tmp["ctr"]= 0
            if pv != 0 :
                tmp["ctr"] = floatformat(click*1.0/pv,arg=-5)
            tmp["cost"]=floatformat(resource_cost_by_day.get(d,0.0),arg=-2)
            tmp["sale_income"]=floatformat(get_cost_by_position(d,pid),arg=-2)
            tmp["bid"]=floatformat(income,arg=-2)
            tmp["profit"]=floatformat(float(tmp["bid"])+float(tmp["sale_income"])-float(tmp["cost"]),arg=-2)
            data.append(tmp)

    except Exception,e:
        logger.exception(e)
        return JsonResponseBadrequest({"message":str(e)})

    positions=[]
    try :
        positions = list(Position.objects.filter(Q(deleted =False),Q(media=position.media)).values("id","name"))
    except :
        positions=[]

    result={
            "data":data,
            "positions":positions,
            "start_date":start_date,
            "end_date":end_date,
            "position_id":pid
    }

    return JsonResponse(result)

@login_required_ajax
def get_position_size(request):
    param = request.GET
    media_id = param.get("media_id")
    try :
        media=None
        size_lst=None
        try :
            media = Media.objects.get(pk=int(media_id),deleted=False)
        except :
            media=None
        if media :
            size_lst  = Position.objects.filter(media = media,deleted=False).values_list("width","height").order_by("width","height").distinct()
        else :
            size_lst = Position.objects.filter(deleted=False).values_list("width","height").order_by("width","height").distinct()
        data_arr =[]
        for s in size_lst :
            tmp = {}
            tmp["width"]=s[0]
            tmp["height"]=s[1]
            data_arr.append(tmp)
        return JsonResponse({"data":data_arr})
    except Exception,e:
        logger.exception(e)
        return JsonResponseBadrequest({"message":str(e)})
    
@login_required_ajax
def get_strategy_report_in_position(request):
    param = request.GET
    position_id = param.get("position_id")
    strategy_id = param.get("strategy_id")
    start = param.get("start")
    end = param.get("end")
    if not request.user.account.is_platform_user() :
        return JsonResponseBadrequest({"message":"no auth"})
    try :
        start = datetime.datetime.strptime(start,"%Y-%m-%d").date()
        end = datetime.datetime.strptime(end,"%Y-%m-%d").date()
        if start >end or end >=datetime.datetime.today().date():
            raise Exception("start or end date is illegal")
        strategy_ids_of_platform = Strategy.objects.filter(organization__type =OrgType.PLATFORM).values_list("id",flat=True)
        strategy_position_data = DailyStrategyPositionReport.objects.filter(strategy=int(strategy_id),date__range=(start,end))
        position_id = int(position_id)
        strategy_id = int(strategy_id)
        if strategy_id not in strategy_ids_of_platform :
            raise Exception("invalid strategy")
        if position_id == -1 :
            strategy_position_data=strategy_position_data.values("date").annotate(
                                                                                  pvs=Sum("pv"),
                                                                                  uvs=Sum("uv"),
                                                                                  clicks = Sum("click"),
                                                                                  costs=Sum("cost")
                                                                                  ).values_list("date","pvs","uvs","clicks","costs")or []
        else :
            strategy_position_data = strategy_position_data.filter(position = int(position_id)).values_list("date","pv","uv","click","cost")or []
        pv_data_by_position_date = {}
        strategy_position_data_by_date ={}
#         获取策略关联的广告位
        positions = __get_positions_by_strategy(strategy_id)
        position_data = DailyPositionReport.objects.filter(date__range = (start,end),position__in=positions).values_list("date","position","pv")
#         （position,date）:pv
        for d in position_data :
            d,p,pv = d
            pv_data_by_position_date[(p,d)] = pv

        for data in strategy_position_data :
            d,pv,uv,click,cost = data
            strategy_position_data_by_date[d]=(pv,uv,click,cost)
            
#         策略关联的所有resource id
        resource_ids = ResourcePrice.objects.filter(strategy=int(strategy_id)).values_list("resource",flat=True)
        
#       根据日期和广告位ID获取关联的traffic
        position_strategy_traffics = Traffic.objects.select_related("position").filter(Q(start__range=(start,end)) | Q(end__range=(start,end))|Q(start__lte=start,end__gte=end)|Q(start__gte=start,end__lte=end),
                                                            Q(deleted=False),
                                                            Q(TRAFFIC__in=resource_ids))
        if position_id != -1 :
            position_strategy_traffics.filter(position=int(position_id)) 
#       返回结果的日期集合
        date_range_arr = date_range_array(start, end)
        
        strategy = Strategy.objects.get(pk=int(strategy_id))
        date_valid = date_region_intersect(start, end, strategy.start, strategy.end)
#         策略的有效日期集合
        date_range_arr_strategy=[]
        if len(date_valid) ==2 :
            date_range_arr_strategy= date_range_array(date_valid[0], date_valid[1])
#       计算媒体花费   
        position_strategy_traffics_cost_by_day = __get_strategy_media_cost_by_day(position_strategy_traffics, strategy_position_data_by_date,pv_data_by_position_date,date_range_arr_strategy)
        data = []
        for d in date_range_arr :
            pv,uv,click,income = strategy_position_data_by_date.get(d,(0,0,0,0))
            tmp = {}
            tmp["date"]=d.strftime("%Y-%m-%d")
            tmp["pv"]=pv
            tmp["uv"]=uv
            tmp["click"]=click
            tmp["ctr"]= 0
            if pv != 0 :
                tmp["ctr"] = click*1.0/pv
            tmp["cost"]=position_strategy_traffics_cost_by_day.get(d,0.0)
            tmp["bid"]=income
            data.append(tmp)
        result={
            "data":data,
            "strategy_id":strategy_id,
            "start_date":start,
            "end_date":end,
            "position_id":position_id
            }
        result["positions"] = [{"id":p.id,"name":p.name,"type":p.media.type} for p in positions]
        return JsonResponse(result)
    except Exception,e:
        logger.exception(e)
        return JsonResponseBadrequest({"message":str(e)})
    
    
def __get_positions_by_strategy(sid ):
    resources_ids = ResourcePrice.objects.filter(strategy=int(sid)).values_list("resource",flat=True)
    traffic_ids = Resource.objects.filter(id__in = resources_ids).values_list("traffic",flat=True)
    position_ids = Traffic.objects.filter(id__in = traffic_ids).values_list("position",flat=True)
    ps = Position.objects.filter(id__in=position_ids)
    return ps

def __get_media_cost_by_day(traffics,base_data_by_day,date_range_arr):
    """
    traffics 流量集合
    base_data_by_day 基础数据（pv,uv,click,cost）按天的map
    date_range_arr 获取数据的日期集合
    """
    media_cost_by_day = dict([(d,0) for d in date_range_arr])
    if date_range_arr :
        for traffic in traffics :
            date_region  = date_region_intersect(date_range_arr[0], date_range_arr[-1], traffic.start, traffic.end)
            if date_region :
                min_date = date_region[0]
                max_date = date_region[1]
                while min_date<=max_date :
                    if traffic.bid_type == 0 :
                        media_cost_by_day[min_date]+=traffic.bid_price
                    elif traffic.bid_type==1 :
                        media_cost_by_day[min_date]+=base_data_by_day.get(min_date,(0,0,0,0))[0]*1.0*traffic.bid_price/1000
                    min_date +=datetime.timedelta(days=1)
    return media_cost_by_day

def __get_strategy_media_cost_by_day(traffics,base_data_by_day,position_pv_data_by_day,date_range_arr):
    """
    traffics 流量集合
    base_data_by_day 基础数据（pv,uv,click,cost）按天的map
    position_pv_data_by_day 关联广告位的按天pv {(position,date):pv}
    date_range_arr 获取数据的日期集合
    """
    media_cost_by_day = dict([(d,0) for d in date_range_arr])
    if date_range_arr :
        for traffic in traffics :
            date_region  = date_region_intersect(date_range_arr[0], date_range_arr[-1], traffic.start, traffic.end)
            if date_region :
                min_date = date_region[0]
                max_date = date_region[1]
                while min_date<=max_date :
                    if traffic.bid_type == 0 :
                        pv_position = position_pv_data_by_day.get((traffic.position.id,d),0) 
                        pv_strategy = base_data_by_day.get(d,(0,0,0,0))[0]
                        rate =0 
                        if pv_position != 0 :
                            rate = pv_strategy*1.0/pv_position
                        media_cost_by_day[d]+=traffic.bid_price*rate
                    elif traffic.bid_type==1 :
                        media_cost_by_day[d]+=base_data_by_day.get(d,(0,0,0,0))[0]*1.0*traffic.bid_price/1000
                    min_date +=datetime.timedelta(days=1)
    return media_cost_by_day